package cc.idoone.codegen.table.query;

import cc.idoone.codegen.config.DataSourceConfig;
import cc.idoone.codegen.table.ColumnJavaType;
import cc.idoone.codegen.table.TableField;
import cc.idoone.codegen.table.TableInfo;
import cc.idoone.codegen.table.TableInfoQuery;
import cc.idoone.codegen.util.StringUtils;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @auther hemj
 * @since 2020/8/25
 */
public class MysqlTableInfoQuery extends TableInfoQuery {
	public static final String tablesSql = "show tables";
	public static final String tableCommentsSql = "show table status";
	public static final String tableFieldsSql = "show full fields from %s";

	public MysqlTableInfoQuery(DataSourceConfig dataSource) {
		this.dataSource = dataSource;
	}

	@Override
	public TableInfo queryTableInfo(String tableName) throws ClassNotFoundException, SQLException {
		PreparedStatement preparedStatement = null;
		try {
			preparedStatement = getConn().prepareStatement(String.format(tableCommentsSql, tableName));
			ResultSet results = preparedStatement.executeQuery();
			TableInfo tableInfo;
			while (results.next()) {
				String name = results.getString("NAME");
				String tableComment = results.getString("COMMENT");
				if (tableName.equals(name)) {
					tableInfo = new TableInfo();
					tableInfo.setName(tableName);
					tableInfo.setComment(tableComment);
					tableInfo.setFields(getTableFields(tableName));
					return tableInfo;
				}
			}
			System.out.println("数据表不存在 " + tableName);
			return null;
		} finally {
			try {
				if (preparedStatement != null) {
					preparedStatement.close();
				}
			} catch (SQLException e) {
			}
		}
	}

	/**
	 * 获取数据库表字段信息
	 */
	private List<TableField> getTableFields(String tableName) throws SQLException, ClassNotFoundException {
		PreparedStatement preparedStatement = null;
		try {
			preparedStatement = getConn().prepareStatement(String.format(tableFieldsSql, tableName));
			ResultSet results = preparedStatement.executeQuery();
			List<TableField> fieldList = new ArrayList<>();
			// 只设置一个主键，并放到最前面
			boolean foundKey = false;
			while (results.next()) {
				TableField field = new TableField();
				field.setName(results.getString("FIELD"));
				field.setType(results.getString("TYPE"));
				field.setComment(results.getString("COMMENT"));
				field.setPropertyName(StringUtils.underlineToCamel(field.getName()));
				field.setColumnType(getJavaType(field.getType()));
				if (field.getName().startsWith("field_") || field.getName().startsWith("FIELD_")) {
					continue; // 备用字段
				}
				// PRIMARY KEY
				String key = results.getString("KEY");
				if (!foundKey && StringUtils.isNotEmpty(key) && key.toUpperCase().equals("PRI")) {
					field.setPrimaryKey(true);
					foundKey = true;
				}
				if (field.isPrimaryKey())
					fieldList.add(0, field);
				else
					fieldList.add(field);
			}
			return fieldList;
		} finally {
			try {
				if (preparedStatement != null) {
					preparedStatement.close();
				}
			} catch (SQLException e) {
			}
		}
	}

	/**
	 * 获取数据库字段对应的JAVA类型
	 */
	private ColumnJavaType getJavaType(String fieldType) {
		String t = fieldType.toLowerCase();
		if (t.contains("char") || t.contains("text")) {
			return ColumnJavaType.STRING;
		} else if (t.contains("bigint")) {
			return ColumnJavaType.LONG;
		} else if (t.contains("int")) {
			return ColumnJavaType.INTEGER;
		} else if (t.contains("date") || t.contains("time") || t.contains("year")) {
			return ColumnJavaType.DATE;
		} else if (t.contains("text")) {
			return ColumnJavaType.STRING;
		} else if (t.contains("bit")) {
			return ColumnJavaType.BOOLEAN;
		} else if (t.contains("decimal")) {
			return ColumnJavaType.BIG_DECIMAL;
		} else if (t.contains("numeric")) {
			return ColumnJavaType.BIG_DECIMAL;
		} else if (t.contains("clob")) {
			return ColumnJavaType.CLOB;
		} else if (t.contains("blog")) {
			return ColumnJavaType.BLOB;
		} else if (t.contains("binary")) {
			return ColumnJavaType.BYTE_ARRAY;
		} else if (t.contains("float")) {
			return ColumnJavaType.FLOAT;
		} else if (t.contains("double")) {
			return ColumnJavaType.DOUBLE;
		} else if (t.contains("json") || t.contains("enum")) {
			return ColumnJavaType.STRING;
		}
		return ColumnJavaType.STRING;
	}
}
